package com.company.project.core.exception;

import com.company.project.core.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

/**
 * =================================
 * <p>
 * Created by cjj on 18-10-17.
 * <p>
 * 描述: 在执行@RequestMapping时，进入逻辑处理阶段前。比如传的参数类型错误进行异常捕获
 * 以上都正常时，在controller里执行逻辑代码时出的异常。比如NullPointerException。
 */

@ControllerAdvice
public class GlobalExceptionHandler {


    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ResponseBody
    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        BindingResult bindingResult = ex.getBindingResult();
        String errorMesssage = "Invalid Request:";

        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            errorMesssage += fieldError.getDefaultMessage() + ";";
        }
        logger.error(errorMesssage);
        return new Result(400, errorMesssage);
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ResponseBody
    public Result handleHttpMessageNotReadableException(HttpMessageNotReadableException ex) {
        return new Result(400, ex.getRootCause().getMessage());
    }

    /**
     * 空指针异常捕获
     *
     * @param e 异常对象
     * @return 异常结果集
     */
    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public Result nullPointerException(NullPointerException e) {
        logger.error("运行时异常", e);
        ExceptionEnum exception = ExceptionEnum.NULL_POINTER_EXCEPTION;
        return new Result(exception.getCode(), exception.getMsg());
    }

    /**
     * 类型强制转换异常捕获
     *
     * @param e 异常对象
     * @return 异常结果集
     */
    @ExceptionHandler(value = ClassCastException.class)
    @ResponseBody
    public Result classCastException(ClassCastException e) {
        logger.error("运行时异常", e);
        ExceptionEnum exception = ExceptionEnum.CLASS_CAST_EXCEPTION;
        return new Result(exception.getCode(), exception.getMsg());
    }

    /**
     * 传递非法参数异常捕获
     *
     * @param e 异常对象
     * @return 异常结果集
     */
    @ExceptionHandler(value = IllegalArgumentException.class)
    @ResponseBody
    public Result illegalArgumentException(IllegalArgumentException e) {
        logger.error("运行时异常", e);
        ExceptionEnum exception = ExceptionEnum.ILLEAGAL_ARGUMENT_EXCEPTION;
        return new Result(exception.getCode(), exception.getMsg());
    }

    /**
     * 算术运算异常捕获
     *
     * @param e 异常对象
     * @return 异常结果集
     */
    @ExceptionHandler(value = ArithmeticException.class)
    @ResponseBody
    public Result arithmeticException(ArithmeticException e) {
        logger.error("运行时异常", e);
        ExceptionEnum exception = ExceptionEnum.ARITHMETIC_EXCEPTION;
        return new Result(exception.getCode(), exception.getMsg());
    }

    /**
     * 向数组中存放与声明类型不兼容对象异常捕获
     *
     * @param e 异常对象
     * @return 异常结果集
     */
    @ExceptionHandler(value = ArrayStoreException.class)
    @ResponseBody
    public Result arrayStoreException(ArrayStoreException e) {
        logger.error("运行时异常", e);
        ExceptionEnum exception = ExceptionEnum.ARRAY_STORE_EXCEPTION;
        return new Result(exception.getCode(), exception.getMsg());
    }

    /**
     * 下标越界异常
     *
     * @param e 异常对象
     * @return 异常结果集
     */
    @ExceptionHandler(value = IndexOutOfBoundsException.class)
    @ResponseBody
    public Result indexOutOfBoundsException(IndexOutOfBoundsException e) {
        logger.error("运行时异常", e);
        ExceptionEnum exception = ExceptionEnum.INDEX_OUT_OF_BOUNDS_EXCEPTION;
        return new Result(exception.getCode(), exception.getMsg());
    }

    /**
     * 创建一个大小为负数的数组错误异常捕获
     *
     * @param e 异常对象
     * @return 异常结果集
     */
    @ExceptionHandler(value = NegativeArraySizeException.class)
    @ResponseBody
    public Result negativeArraySizeException(NegativeArraySizeException e) {
        logger.error("运行时异常", e);
        ExceptionEnum exception = ExceptionEnum.NEGATIVE_ARRAY_SIZE_EXCEPTION;
        return new Result(exception.getCode(), exception.getMsg());
    }

    /**
     * 数字格式异常捕获
     *
     * @param e 异常对象
     * @return 异常结果集
     */
    @ExceptionHandler(value = NumberFormatException.class)
    @ResponseBody
    public Result numberFormatException(NumberFormatException e) {
        logger.error("运行时异常", e);
        ExceptionEnum exception = ExceptionEnum.NUMBER_FORMAT_EXCEPTION;
        return new Result(exception.getCode(), exception.getMsg());
    }

    /**
     * 安全异常捕获
     *
     * @param e 异常对象
     * @return 异常结果集
     */
    @ExceptionHandler(value = SecurityException.class)
    @ResponseBody
    public Result securityException(SecurityException e) {
        logger.error("运行时异常", e);
        ExceptionEnum exception = ExceptionEnum.SECURITY_EXCEPTION;
        return new Result(exception.getCode(), exception.getMsg());

    }

    /**
     * 不支持的操作异常捕获
     *
     * @param e 异常对象
     * @return 异常结果集
     */
    @ExceptionHandler(value = UnsupportedOperationException.class)
    @ResponseBody
    public Result unsupportedOperationException(UnsupportedOperationException e) {
        logger.error("运行时异常", e);
        ExceptionEnum exception = ExceptionEnum.UNSUPPORTED_OPERATION_EXCEPTION;
        return new Result(exception.getCode(), exception.getMsg());
    }

    /**
     * 参数绑定异常捕获
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public Result handleBindException(BindException ex) {
        // ex.getFieldError():随机返回一个对象属性的异常信息。如果要一次性返回所有对象属性异常信息，则调用ex.getAllErrors()
        FieldError fieldError = ex.getFieldError();
        StringBuilder sb = new StringBuilder();
        sb.append(fieldError.getField()).append("=[").append(fieldError.getRejectedValue()).append("]")
                .append(fieldError.getDefaultMessage());
        // 生成返回结果
        logger.error("参数绑定异常", sb.toString());
        return new Result(-1, sb.toString());
    }

    /**
     * 自定义异常捕获
     *
     * @param e 异常对象
     * @return 异常结果集
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public Result businessException(BusinessException e) {
        logger.error("运行时异常", e);
        return new Result(e.getCode(), e.getMsg());
    }
}
